Skip to content

feature/NestedBreakWithLabel #510

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

Yi2255
Copy link
Contributor

@Yi2255 Yi2255 commented Apr 29, 2025

Hi Saelo,

First of all, I sincerely apologize for the long delay regarding the implementation of LabelStatement.
Following your suggestion #479, I have split this feature into two separate PRs, LoopContinueNested and NestedBreak.
This PR specifically addresses the issue of NestedBreak. I have restructured the approach as follows:


Here is the ECMA definition of LabelStatement:

LabeledStatement:
  Identifier : Statement

And the full enumeration of Statement types:

Statement ::= 
  BlockStatement
  | BreakStatement
  | ContinueStatement
  | DebuggerStatement
  | DoWhileStatement
  | EmptyStatement
  | ExpressionStatement
  | ForStatement
  | ForInStatement
  | ForOfStatement
  | FunctionDeclaration
  | IfStatement
  | LabeledStatement
  | ReturnStatement
  | SwitchStatement
  | ThrowStatement
  | TryStatement
  | VariableDeclaration
  | WhileStatement
  | WithStatement
  | ClassDeclaration
  | ImportDeclaration
  | ExportDeclaration

However, not all Statement types can meaningfully work with a label.
Here is my analysis of statements that should not be considered:

  1. Declaration Statements

    Labels can only be applied to statements, not declarations.

    L: function F() {}

    Thus, all declaration-related statements can be ignored, as this is only a legacy behavior with no practical significance.

  2. DebuggerStatement

    This only exists in the trivial form of label: debugger;, which we can safely ignore.

  3. ExpressionStatement

    ExpressionStatement :
      [lookahead  { '{' , 'function' , 'class' , 'let' , 'async function' }] Expression ;

    Since a LabelStatement must be followed by a single valid Statement, ExpressionStatements are essentially limited to cases like label: break label;, which are not meaningful for our purposes.

  4. ReturnStatement

    A return statement causes a function to cease execution and usually returns a value to the caller. A return may not always return depending on surrounding contexts such as try-finally blocks.

    Since return is only allowed inside function bodies, it cannot properly be labeled.


After excluding the above, the remaining valid statements that can be used with a label are:

  1. IfStatement
  2. TryStatement
  3. WithStatement
  4. BlockStatement
  5. SwitchStatement
  6. Loop Family
    • DoWhileStatement
    • ForStatement
    • ForInStatement
    • ForOfStatement
    • WhileStatement

This matches the examples you previously mentioned.
Importantly, all valid label targets are recursive structures, which means that the existing loopLabelStack design can be reused.


Here are some detailed points about the implementation:

  1. Fuzzilli does not abstract basic grammar types like Statement and Expression.
    Therefore, it is not possible to batch-handle statements generically.

  2. Labeling cannot be universally applied to every JS context as you initially suggested.
    A label must anchor the beginning of a code block; otherwise, a break would not know its valid break target.

  3. Fuzzilli’s context system is designed top-down.
    Even though JavaScript has a unified break; statement, in Fuzzilli the context system using isSubSet(of: originContext) enforces the separation of different break types.
    Therefore, I chose to follow the existing architectural style: implement a dedicated xxxNestedBreak for each context, instead of creating a generic nestedBreak.

  4. I have extended the context system by adding three missing contexts: ifBlock, tryBlock, and codeBlock.
    Based on this, I have implemented six NestedBreak operations:

    • switchNestedBreak
    • blockNestedBreak
    • ifNestedBreak
    • withNestedBreak
    • tryNestedBreak
    • loopNestedBreak

    I also restructured the auxiliary stacks needed for these operations, ensuring that multiple labeled statements can coexist and be reused properly.
    I sincerely appreciate your patience and understanding!

@Yi2255
Copy link
Contributor Author

Yi2255 commented Apr 30, 2025

As a supplement, Fuzzilli’s context design is top-down, which means there is no unified solution for the same operation appearing in different contexts. For example, although switchBreak and loopBreak both correspond to break; in JavaScript, the current architecture—based on isSubSet(of: originContext) in ProgramBuilder.swift—makes it necessary to implement them separately. Therefore, I’ve decided to follow the existing design approach by implementing a dedicated xxxNestedBreak operation for each context, rather than introducing a generic nestedBreak.
//ProgramBuilder.swift
availableGenerators = fuzzer.codeGenerators.filter({ $0.requiredContext.isSubset(of: origContext) })

@Yi2255 Yi2255 closed this Apr 30, 2025
@Yi2255 Yi2255 deleted the feature-NestedBreak branch April 30, 2025 04:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant